REST API AI Coding Rules

REST API AI rules help engineering teams get better results from AI coding assistants like Cursor, Windsurf, and GitHub Copilot. By defining clear conventions for code style, architecture patterns, error handling, and module organisation, REST API AI rules ensure that generated code is consistent, maintainable, and production-ready. Whether you are working on a side project or a large-scale enterprise system, community-curated rules on AI Rules Hub provide a solid foundation you can adopt instantly and customise to fit your team's standards.

Why Use AI Rules for REST API?

  • Ensure AI-generated REST API code follows your team's conventions
  • Prevent common anti-patterns that degrade maintainability
  • Reduce code review cycles by getting AI output right the first time
  • Standardise error handling, logging, and module structure
  • Make AI assistants produce secure and performance-conscious code

Best Practices for REST API AI Coding

Define a Consistent Code Style

Specify formatting preferences (indentation, quotes, trailing commas) for REST API so AI output matches your linter configuration without manual edits.

Enforce Error Handling Patterns

Instruct AI to always handle errors explicitly, use structured logging, and avoid swallowing exceptions silently.

Set Module Organisation Rules

Define how REST API modules should be organised — feature folders, barrel exports, and separation of concerns — so AI keeps the project structure clean.

Require Security-Conscious Patterns

Add rules that enforce input validation, sanitisation, and safe dependency usage so AI never introduces obvious security vulnerabilities.

Common Patterns & Standards

#01

Separation of Concerns

Keep business logic, data access, and presentation layers separate in REST API projects so each layer is independently testable.

#02

Dependency Injection

Pass dependencies explicitly through constructors or function parameters — avoiding global state that makes testing difficult.

#03

Consistent Naming Conventions

Rule AI to follow REST API community naming standards for files, classes, functions, and constants.

#04

Automated Testing Standards

Define what test types are required (unit, integration) and where test files should live so AI generates tests alongside implementation code.

Top REST API Rules on AI Rules Hub

This guide provides a production-ready architectural pattern for implementing TanStack Query in a React application. It focuses on scalability, type safety, and maintainability.

# The Guide to TanStack Query (React Query) in React + Vite + TypeScript

This guide provides a production-ready architectural pattern for implementing TanStack Query in a React application. It focuses on scalability, type safety, and maintainability.

## 1. Installation & Setup

First, install the core package and the devtools.

```bash
npm install @tanstack/react-query @tanstack/react-query-devtools axios
```

### Global Configuration (`src/main.tsx`)

Wrap your application in `QueryClientProvider`.

```tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import App from './App';

// Create a client
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60 * 5, // Data is fresh for 5 minutes
      gcTime: 1000 * 60 * 60, // Garbage collect unused data after 1 hour
      retry: 1, // Retry failed requests once
      refetchOnWindowFocus: false, // Prevent refetching on window focus (optional)
    },
  },
});

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
      {/* DevTools are essential for debugging */}
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  </StrictMode>
);
```

---

## 2. Recommended Directory Structure

Isolate your data fetching logic from your UI components.

```
src/
├── api/                # Pure Axios/Fetch functions
│   ├── axios-client.ts # configured axios instance
│   └── todos.api.ts    # API methods for a specific feature
├── hooks/              # Custom React Query hooks
│   └── queries/        # Group hooks by feature
│       └── useTodos.ts
├── types/              # TypeScript interfaces
│   └── todo.types.ts
└── lib/
    └── query-keys.ts   # Centralized query keys
```

---

## 3. Query Key Factory Pattern (`src/lib/query-keys.ts`)

**Crucial:** Never hardcode query keys (strings/arrays) directly in your components. Use a factory to maintain consistency.

```typescript
// src/lib/query-keys.ts
export const todoKeys = {
  all: ['todos'] as const,
  lists: () => [...todoKeys.all, 'list'] as const,
  list: (filters: string) => [...todoKeys.lists(), { filters }] as const,
  details: () => [...todoKeys.all, 'detail'] as const,
  detail: (id: number) => [...todoKeys.details(), id] as const,
};
```

---

## 4. The API Layer (`src/api/*`)

Keep API calls strictly as pure functions returning Promises. They should know nothing about React.

```typescript
// src/api/todos.api.ts
import axios from 'axios';
import { Todo } from '../types/todo.types';

const api = axios.create({ baseURL: 'https://jsonplaceholder.typicode.com' });

export const fetchTodos = async (): Promise<Todo[]> => {
  const { data } = await api.get('/todos');
  return data;
};

export const fetchTodoById = async (id: number): Promise<Todo> => {
  const { data } = await api.get(`/todos/${id}`);
  return data;
};

export const createTodo = async (newTodo: Omit<Todo, 'id'>): Promise<Todo> => {
  const { data } = await api.post('/todos', newTodo);
  return data;
};
```

---

## 5. Custom Hooks (The "Glue" Layer)

Wrap `useQuery` and `useMutation` in custom hooks. This gives you a single place to handle key management, types, and default options.

### Fetching Data (`useQuery`)

```typescript
// src/hooks/queries/useTodos.ts
import { useQuery } from '@tanstack/react-query';
import { todoKeys } from '../../lib/query-keys';
import { fetchTodos, fetchTodoById } from '../../api/todos.api';

export const useTodos = () => {
  return useQuery({
    queryKey: todoKeys.lists(),
    queryFn: fetchTodos,
    staleTime: 1000 * 60, // 1 minute specific stale time for this query
  });
};

export const useTodo = (id: number) => {
  return useQuery({
    queryKey: todoKeys.detail(id),
    queryFn: () => fetchTodoById(id),
    enabled: !!id, // Only run if ID is present
  });
};
```

### Mutating Data (`useMutation`)

Always invalidate related queries on success to keep the UI in sync.

```typescript
// src/hooks/queries/useTodos.ts
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { createTodo } from '../../api/todos.api';
import { todoKeys } from '../../lib/query-keys';

export const useCreateTodo = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: createTodo,
    onSuccess: () => {
      // Invalidate the 'lists' query so the new item appears
      queryClient.invalidateQueries({ queryKey: todoKeys.lists() });
    },
    onError: (error) => {
      console.error('Failed to create todo:', error);
    },
  });
};
```

---

## 6. Usage in Components

Components become clean and focused purely on UI logic.

```tsx
// src/components/TodoList.tsx
import { useTodos, useCreateTodo } from '../hooks/queries/useTodos';

export const TodoList = () => {
  const { data: todos, isLoading, isError } = useTodos();
  const createMutation = useCreateTodo();

  if (isLoading) return <div>Loading...</div>;
  if (isError) return <div>Error fetching todos</div>;

  const handleCreate = () => {
    createMutation.mutate({ title: 'New Task', completed: false, userId: 1 });
  };

  return (
    <div>
      <button onClick={handleCreate} disabled={createMutation.isPending}>
        {createMutation.isPending ? 'Adding...' : 'Add Todo'}
      </button>

      <ul>
        {todos?.map((todo) => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
    </div>
  );
};
```

---

## 7. Advanced Patterns

### Optimistic Updates

Update the UI _immediately_ before the server responds.

```typescript
export const useUpdateTodo = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: updateTodoApi,
    onMutate: async (newTodo) => {
      // 1. Cancel outgoing refetches
      await queryClient.cancelQueries({ queryKey: todoKeys.detail(newTodo.id) });

      // 2. Snapshot previous value
      const previousTodo = queryClient.getQueryData(todoKeys.detail(newTodo.id));

      // 3. Optimistically update
      queryClient.setQueryData(todoKeys.detail(newTodo.id), (old: any) => ({
        ...old,
        ...newTodo,
      }));

      // 4. Return context
      return { previousTodo };
    },
    onError: (err, newTodo, context) => {
      // 5. Rollback on error
      queryClient.setQueryData(todoKeys.detail(newTodo.id), context?.previousTodo);
    },
    onSettled: (newTodo) => {
      // 6. Refetch to ensure server sync
      queryClient.invalidateQueries({ queryKey: todoKeys.detail(newTodo?.id) });
    },
  });
};
```

### Type-Safe Error Handling

Define a global error type for your API.

```typescript
// types/api.types.ts
export interface ApiError {
  message: string;
  statusCode: number;
}

// In custom hook
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
import { ApiError } from '../types/api.types';

export const useTodos = (options?: UseQueryOptions<Todo[], ApiError>) => {
  return useQuery({
    queryKey: todoKeys.lists(),
    queryFn: fetchTodos,
    ...options,
  });
};
```

---

## 8. Best Practices Checklist

- [ ] **Global Stale Time**: Set a reasonable global `staleTime` (e.g., 5 mins) to avoid excessive background fetching.
- [ ] **Query Key Factories**: Always use a factory/object for keys (`todoKeys.list(filter)`).
- [ ] **Separation of Concerns**: `Component` -> `Custom Hook` -> `API Function`.
- [ ] **Invalidation**: Always invalidate parent lists when creating/deleting items.
- [ ] **DevTools**: Keep `ReactQueryDevtools` in your app wrapper (it's stripped in production).
19 views

Share Your REST API AI Rules

Have rules that improved your REST API workflow? Submit them to AI Rules Hub and help the community get better results from AI coding assistants.

Frequently Asked Questions

REST API AI rules are context files (like `.cursorrules` or `AGENTS.md`) that instruct AI coding assistants to follow REST API best practices — covering code style, architecture, error handling, and testing conventions.

Command Palette

Search for a command to run...